package com.yssw.onlinechat.service.impl;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yssw.onlinechat.domain.OnlineChatUser;
import com.yssw.onlinechat.dto.SocketMsg;
import com.yssw.onlinechat.service.WebSocketService;
import com.yssw.task.SaveChatRecordsTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @author GL
 */
@Service
@ServerEndpoint("/websocket/{userName}")
@Slf4j
public class WebSocketServiceImpl implements WebSocketService , InitializingBean {

    private String userName;
    private Session session;
    private static final String server = "server";


    @Autowired
    private  SaveChatRecordsTask task;

    private static CopyOnWriteArraySet<WebSocketServiceImpl> socketSet = new CopyOnWriteArraySet<WebSocketServiceImpl>();



    /**
     * 这里做消息的暂存
     * 用户IP为Key 记录为value
     */
    public static Map<String, OnlineChatUser> userMap;

    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     * 用来记录sessionId和该session进行绑定
     */
    private static   ConcurrentHashMap<String, Session> map = new ConcurrentHashMap();

    @Override
    public void afterPropertiesSet() throws Exception {
        userMap=task.get();
        if (userMap==null) {
            userMap=new ConcurrentHashMap<>(10);
        }
    }
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    @Override
    public synchronized void onOpen(Session session, @PathParam("userName") String userName) throws IOException {
        ConcurrentHashMap<String, Object> message = new ConcurrentHashMap(3);
        this.session = session;
        this.userName = userName;
        String id = userName;
        map.put(id, session);
        //加入set中
        synchronized (session) {
            if (userName.equals(server)) {
                socketSet.add(this);
                log.info("服务端连接成功");
                message.put("userList", new ArrayList<>(userMap.values()));
            } else {
                socketSet.add(this);
                log.info("有新连接加入:" + userName + ",当前客户端在线人数为" + socketSet.size());
                //给它创建一个历史记录的array
                if (ObjectUtils.isEmpty(userMap.get(userName))) {
                    userMap.put(userName,
                            new OnlineChatUser(new CopyOnWriteArrayList<>(), true, userName, 0));
                } else {
                    userMap.get(userName).setStatus(true);
                }
//                task.save(userMap);
                //给服务端发送消息，通知有新的用户进来了，返回新用户id
                Session noticeSession = map.get(server);
                if (noticeSession != null && noticeSession.isOpen()) {
                    ConcurrentHashMap<String, Object> noticeMap = new ConcurrentHashMap<>(2);
                    noticeMap.put("msg", "有新的客户发起对话");
                    noticeMap.put("userList", new CopyOnWriteArrayList<>(userMap.values()));
                    synchronized (noticeSession) {
                        noticeSession.getBasicRemote().sendText(JSON.toJSONString(noticeMap));

                    }
                }
            }
            message.put("msg", "连接成功");

            if (session != null && session.isOpen()) {
                synchronized (session) {
                    session.getAsyncRemote().sendText(JSON.toJSONString(message));
                }
            }

        }
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    @Override
    public void onClose() throws IOException {

        socketSet.remove(this);
        if (!userName.equals(server)) {

            userMap.get(userName).setStatus(false);
        }
//        task.save(userMap);
        //给服务端发送消息，通知有用户退出，返回新用户id
        Session noticeSession = map.get(server);
        if (noticeSession != null && noticeSession.isOpen()) {
            ConcurrentHashMap<String, Object> noticeMap = new ConcurrentHashMap<>(2);

            noticeMap.put("msg", userName + " 用户退出");
            noticeMap.put("userList", new CopyOnWriteArrayList<>(userMap.values()));

            synchronized (noticeSession) {
                noticeSession.getBasicRemote().sendText(JSON.toJSONString(noticeMap));

            }
        }
        log.info("有一连接关闭！当前客户端在线人数为" + socketSet.size());


    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    @Override
    public void onMessage(String message, Session session,
                          @PathParam("userName") String userName) throws IOException {

        log.info("来自客户端的消息-->" + userName + ": " + message);

        //从客户端传过来的数据是json数据，所以这里使用jackson进行转换为SocketMsg对象，
        ObjectMapper objectMapper = new ObjectMapper();
        SocketMsg socketMsg = objectMapper.readValue(message, SocketMsg.class);
        Session serverSession = map.get(server);
        ConcurrentHashMap<String, Object> noticeMap = new ConcurrentHashMap<>(2);
        noticeMap.put("msg", "有用户发来消息");
        noticeMap.put("userList", new CopyOnWriteArrayList<>(userMap.values()));

        if (userName.equals(server)) {
            userMap.get(socketMsg.getToUser()).getHistoryMsg().add(socketMsg);
        } else {
//            int beFor=userMap.get(userName).getHistoryMsg().size();
            userMap.get(userName).getHistoryMsg().add(socketMsg);
//            int concurrent=userMap.get(userName).getHistoryMsg().size();
//            userMap.get(userName).setUnreadNum((concurrent-beFor));
        }
        if (serverSession != null && serverSession.isOpen()) {
            String s = JSON.toJSONString(noticeMap);
            serverSession.getBasicRemote().sendText(s);
        }

        //找到发送者和接受者.
        //发送者
        Session fromSession = map.get(socketMsg.getFromUser());

        Session toSession = map.get(socketMsg.getToUser());

        if (toSession != null && toSession.isOpen()) {
            log.info(socketMsg.toString());
            toSession.getBasicRemote().sendText(JSON.toJSONString(socketMsg));
        } else if (fromSession != null && fromSession.isOpen()) {
            //发送给发送者
            synchronized (fromSession) {
                fromSession.getAsyncRemote().sendText("系统消息：对方不在线或者您输入的频道号不对");

            }
        }
    }


    /**
     * 发生错误时调用
     */
    @OnError
    @Override
    public void onError(Session session, Throwable error) throws IOException {
        error.printStackTrace();
//        task.save(userMap);
        log.error("服务异常");
    }


}
